package cn.cosmosx.base.encrypt.aes;

import cn.cosmosx.base.encrypt.hex.HexUtil;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.NoSuchAlgorithmException;
import java.util.Objects;

/**
 * AES算法工具（基于ECB算法模式）
 * 秘钥仅支持128位
 */
@Slf4j
public class AESUtil {
    // aes加解密秘钥：可配置到Constant中，并读取配置文件注入,16位,自己定义
    private static final String DEFAULT_SECRET_KEY = "8d55ab0b1b2ac5452f4362aa77691911";
    private static final String ALGORITHM = "AES";
    // 算法模式：参数分别代表 算法名称/加密模式/数据填充方式
    private static final String MODE = "AES/ECB/PKCS5Padding";
    private static final Charset CHARSET = StandardCharsets.UTF_8;

    /**
     * 加密
     *
     * @param src - 明文
     */
    public static String encrypt(String src) {
        return encrypt(src, DEFAULT_SECRET_KEY);
    }

    /**
     * 解密
     *
     * @param contextHex - 密文
     */
    public static String decrypt(String contextHex) {
        return decrypt(contextHex, DEFAULT_SECRET_KEY);
    }

    /**
     * 加密
     *
     * @param src  - 明文
     * @param sKey - AES秘钥
     */
    public static String encrypt(String src, String sKey) {
        try {
            Cipher cipher = Cipher.getInstance(MODE);// "算法/模式/补码方式"
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(HexUtil.decodeStrict(sKey), ALGORITHM));
            byte[] encrypted = cipher.doFinal(src.getBytes(CHARSET));
            return HexUtil.toHexString(encrypted);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 解密
     *
     * @param contextHex - 密文
     * @param sKey       - AES秘钥
     */
    public static String decrypt(String contextHex, String sKey) {
        try {
            Cipher cipher = Cipher.getInstance(MODE);
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(HexUtil.decodeStrict(sKey), ALGORITHM));
            return new String(cipher.doFinal(HexUtil.decodeStrict(contextHex)), CHARSET);
        } catch (Exception ex) {
            return null;
        }
    }

    /**
     * 生成AES秘钥
     * <p>
     * 生成一个128位的私钥
     */
    public static SecretKey generateSecretKey() {
        try {
            // 拿到没要生成器
            KeyGenerator generator = KeyGenerator.getInstance(ALGORITHM);
            // 设置生成秘钥
            generator.init(128);
            return generator.generateKey();
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
    }

    /**
     * 生成AES秘钥十六进制
     */
    public static String generateSecretHex() {
        return HexUtil.toHexString(Objects.requireNonNull(generateSecretKey()).getEncoded());
    }

    /**
     * 获得AES秘钥SecretKey
     */
    public static SecretKey getSecretKey(String sKey) {
        return new SecretKeySpec(HexUtil.decodeStrict(sKey), ALGORITHM);
    }

    /**
     * 保存秘钥到文件
     *
     * @param secretKeyPath - AES秘钥证书路径
     */
    public static Path saveSecretKey(String secretKeyPath) throws IOException {
        String keys = HexUtil.toHexString(Objects.requireNonNull(generateSecretKey()).getEncoded());
        log.info("生成的AES secret keys HexUtil: {}", keys);
        return Files.write(Paths.get(secretKeyPath), keys.getBytes(CHARSET));
    }

    /**
     * 加载文件秘钥
     *
     * @param secretKeyPath - AES秘钥证书路径
     */
    public static SecretKey loadSecretKey(String secretKeyPath) throws IOException {
        return new SecretKeySpec(Files.readAllBytes(Paths.get(secretKeyPath)), ALGORITHM);
    }

    /**
     * 加载文件秘钥
     *
     * @param secretKeyPath - AES秘钥证书路径
     */
    public static String loadSecretKeyHex(String secretKeyPath) throws IOException {
        return new String(Files.readAllBytes(Paths.get(secretKeyPath)), CHARSET);
    }

}
